This track can be used for simple transform movements between two points.
This track can be used for simple transform movements. All translation happens in a straight line but the speed can be controlled with an animation curve. The Tween track binds to the scene Transform
you wish to move.
Field | Description |
---|---|
Start Location | This is a reference to a Transform in the scene that marks the position and/or rotation of the moving Transform when the playable starts. If it is left null the position/rotation of the moving Transform when the playable starts will be used. |
End Location | This is a reference to a Transform in the scene that marks the position and/or rotation of the moving Transform when the playable finishes. |
Tween Position | Whether or not the position of the Transform should change. |
Tween Rotation | Whether or not the rotation of the Transform should change. |
This example will demonstrate how to:
ClipEditor
;when a Timeline begins playing, nodes called Playable
s are created. They are organized in a tree-like structure called the PlayableGraph
. For each frame, Timeline samples this graph to read and mix multiple data sources (animation, audio and more).
The first step to create a custom clip is to define a new PlayableBehaviour
that will be added to a graph. It will need to store the data needed to implement the transform tween:
public class TweenBehaviour : PlayableBehaviour { public Transform startLocation; public Transform endLocation; public bool shouldTweenPosition; public bool shouldTweenRotation; public AnimationCurve curve; }
The PlayableBehaviour
's data is not serialized and will be lost once its parent graph is destroyed. To save this data, the next step is to define a new PlayableAsset
:
[Serializable] public class TweenClip : PlayableAsset { public ExposedReference<Transform> startLocation; public ExposedReference<Transform> endLocation; public bool shouldTweenPosition = true; public bool shouldTweenRotation = true; public AnimationCurve curve; //... }
Note: The clip needs to store a start and an end location. Since an asset cannot directly reference a scene object, it cannot store a transform object directly. This is why an ExposedReference<Transform>
is used.
A PlayableAsset
's main purpose is to build a PlayableBehaviour
. This is done with the CreatePlayable
method:
public class TweenClip : PlayableAsset { //... public override Playable CreatePlayable(PlayableGraph graph, GameObject owner) { // create a new TweenBehaviour ScriptPlayable<TweenBehaviour> playable = ScriptPlayable<TweenBehaviour>.Create(graph); TweenBehaviour tween = playable.GetBehaviour(); // set the behaviour's data tween.startLocation = startLocation.Resolve(graph.GetResolver()); tween.endLocation = endLocation.Resolve(graph.GetResolver()); tween.curve = curve; tween.shouldTweenPosition = shouldTweenPosition; tween.shouldTweenRotation = shouldTweenRotation; return playable; } }
CreatePlayable
will initialize a new TweenBehaviour
using TweenClip
's data.
A custom track is created by defining a TrackAsset subclass. The following attributes can be added to a TrackAsset
:
For this example, the track needs a Transform
object binding and can only accepts clips of type TweenClip
, which was previously defined in step 1:
[TrackBindingType(typeof(Transform))] [TrackClipType(typeof(TweenClip))] public class TweenTrack : TrackAsset { // ... }
The data setup is complete; TweenTrack
and TweenClip
can now be added to a timeline:
However, no transform tween has been implemented yet. To do this, a track mixer is needed.
To properly handle blending, or crossfading, between two clips, a track mixer is needed. A track mixer is a PlayableBehaviour
that will have access to all clips data and will blend those together.
By default, when a track is added to a timeline, an empty playable is generated and is connected to each clip's playable.
For example, this track:
will generate the following playable graph:
Timeline
: this playable is the root
playable; all playables related to tracks are connected to this node.Playable
: this playable represents the track mixer. Since no track mixer is defined, an empty one is generated.TweenBehaviour
: this playable represents a clip. One per clip is generated. All clip playables are connected to the track mixer.In order to define a custom track mixer, a new PlayableBehaviour
needs to be defined:
public class TweenMixerBehaviour : PlayableBehaviour {}
then, in TrackAsset
, the CreateTrackMixer method can be used to specify a custom track mixer:
public class TweenTrack : TrackAsset { public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) { return ScriptPlayable<TweenMixerBehaviour>.Create(graph, inputCount); } }
Now the playable graph looks like this:
The empty playable that used to connect clip playables together is now replaced by TweenMixerBehaviour
.
The implementation of the transform tween resides in the ProcessFrame
method from TweenMixerBehaviour
. Here are the main steps of that implementation:
null
, the initial transform will be used instead.// Iterate on all the playable's (mixer) inputs (ie each clip on the track) int inputCount = playable.GetInputCount(); for (int i = 0; i < inputCount; i++) { // get the input connected to the mixer Playable input = playable.GetInput(i); // get the weight of the connection float inputWeight = playable.GetInputWeight(i); // get the clip's behaviour TweenBehaviour tweenInput = GetTweenBehaviour(input); }
// Apply the final position and rotation values in the track binding trackBinding.position = accumPosition + m_InitialPosition * (1.0f - totalPositionWeight); trackBinding.rotation = accumRotation.Blend(m_InitialRotation, 1.0f - totalRotationWeight);
ClipEditor
can be used to augment the capabilities of a clip in the editor. It works like a custom Inspector; the CustomTimelineEditor attribute is used to tell Timeline that a ClipEditor class should be associated to a given clip.
[CustomTimelineEditor(typeof(TweenClip))] public class TweenClipEditor : ClipEditor { //... }
It is possible to customize the appearance of a clip with the DrawBackground method:
public override void DrawBackground(TimelineClip clip, ClipBackgroundRegion region) { TweenClip asset = clip.asset as TweenClip; if (asset == null) return; // Drawing code here... }